//
//  Unit.m
//  Hello Cocos
//
//  Created by Tedo on 6/13/10.
//  Copyright 2010 sushigames. All rights reserved.
//

#import "Unit.h"


@implementation Unit

@synthesize touch;
@synthesize desiredPosition;
@synthesize attackTarget;
@synthesize attackElapsed;
@synthesize state;

@synthesize affinityYield;
@synthesize affinityRequirements;
@synthesize attackType;
@synthesize attackRange;
@synthesize attackDamage;
@synthesize attackSpeed;
@synthesize moveSpeed;
@synthesize moveSpeedInCombat;
@synthesize maxHealth;
@synthesize health;
@synthesize name;

static NSMutableArray * allUnits = nil;

+(NSMutableArray *) allUnits {
    @synchronized(allUnits) {
        if (allUnits == nil)
            allUnits = [[NSMutableArray alloc] init];
        return allUnits;
    }
	return nil;
}

+(NSMutableArray *) allUnitsNotDead {
	NSMutableArray *array = [[NSMutableArray alloc] init];
	for (Unit *unit in [Unit allUnits]) {
		if (unit.state != DEAD) {
			[array addObject:unit];
		}
	}
	return array;
}

+(void)track: (Unit *)aUnit {
    @synchronized(allUnits) {
        [[Unit allUnits] addObject:aUnit];
		NSLog( @"Unit Child Count: %d", [[Unit allUnits] count] );
    }
}

+(void)untrack: (Unit *)aUnit {
    @synchronized(allUnits) {
        [[Unit allUnits] removeObject:aUnit];
    }
}

+(void)clearAllUnits {
	@synchronized(allUnits) {
		[[Unit allUnits] removeAllObjects];
		for (Unit* unit in [Unit allUnits]) {
			[unit dealloc];
		}
	}
}

-(id)init {
    self = [super init];
    if (self) {
		touch = nil;
		[Unit track:self];
//		[self schedule:@selector(update:)];
		
		desiredPosition = ccp(-1, -1);
		attackTarget = nil;
		attackElapsed = 0.0;
		state = IDLE;
	}
    return self;
}

+(id)unitFromId:(NSString *)identifier {
	NSString *resource = [[NSBundle mainBundle] pathForResource:@"units" ofType:@"plist"];
	NSDictionary *unitsDictionary = [[NSDictionary alloc] initWithContentsOfFile:resource];
	NSDictionary *unitInfo = [unitsDictionary valueForKey:identifier];
	
	Unit *unit = [Unit spriteWithFile: [unitInfo valueForKey:@"resourcePath"]];
	unit.name = [unitInfo valueForKey:@"name"];
	unit.maxHealth = [[unitInfo valueForKey:@"maxHealth"] floatValue];
	unit.health = unit.maxHealth;
	unit.attackRange = [[unitInfo valueForKey:@"attackRange"] floatValue];
	unit.attackDamage = [[unitInfo valueForKey:@"attackDamage"] floatValue];
	unit.attackSpeed = [[unitInfo valueForKey:@"attackSpeed"] floatValue];
	unit.moveSpeed = [[unitInfo valueForKey:@"moveSpeed"] floatValue];
	unit.moveSpeedInCombat = [[unitInfo valueForKey:@"moveSpeedInCombat"] floatValue];
	unit.affinityYield = [unitInfo valueForKey:@"affinityYield"];
	unit.affinityRequirements = [unitInfo valueForKey:@"affinityRequirements"];
	unit.attackType = (AttackType)[[unitInfo valueForKey:@"attackType"] intValue];
	
	/* 
	 TODO: change format to
	 if ([[unitInfo allKeys] containsObject:@"var"]) 
		unit.var = [unitInfo valueForKey:@"var"];
	 else
		unit.var = nil;
	 */
	
	return unit;
}

-(void)update:(ccTime)dt {
	if (desiredPosition.x != -1 && desiredPosition.y != -1) {
		CGPoint distance = ccpSub(desiredPosition, [self position]);
		if (ccpLength(distance) > 15.0) {
			float speed = 500.0;
			CGPoint move = ccpNormalize(distance);
			CGPoint new = ccpAdd( self.position, ccpMult( move, speed * dt ) );
			self.position = new;
			
			CCNode *parent = [self parent];
			[parent reorderChild:self z:-self.position.y];
		}
	}
}

-(void)changeStateTo:(UnitState)newState {
	// No change
	if (newState == self.state) return;
	
	// Stopped fighting
	if (self.state == ATTACK) {
		self.attackTarget = nil;
		self.attackElapsed = 0.0;
	}
	
	self.state = newState;
}

-(void)changeStateTo:(id)sender data:(UnitState)newState {
	[self changeStateTo:newState];
}

-(void)damaged:(float)damage {
	[self stopActionByTag:1];
	
	CCPropertyAction *damageAction;
	if (self.health - damage > 0) {
		damageAction = [CCPropertyAction actionWithDuration:0.2 
														   key:@"health" 
														  from:self.health 
															to:self.health-damage]; 
		
		damageAction.tag = 1;
		// TODO: this is wrong, health might already be in an damaged action
		
		[self runAction:damageAction];
	}
	else if (self.health - damage > 100) {
		damageAction = [CCPropertyAction actionWithDuration:0.2 
														key:@"health" 
													   from:self.health 
														 to:100]; 
	}
	else {
		damageAction = [CCPropertyAction actionWithDuration:0.2 
														   key:@"health" 
														  from:self.health 
															to:0];
		id damageCallFunc = [CCCallFuncND actionWithTarget:self selector:@selector(changeStateTo:data:) data:(void*)DEAD];
		CCSequence *damageSequence = [CCSequence actions: damageAction, damageCallFunc, nil];
		[self runAction:damageSequence];
	}
}

-(void)draw {
	
	if (state != DEAD) {
		[super draw];
	}
	
	if (state == ATTACK) {
		// Temp display of attack target
		glColor4f(1.0, 1.0, 0.2, 1.0);  
		glLineWidth(5.0f);
		
		if (attackTarget != nil) {
			CGRect unitBB = [self boundingBox];
			CGPoint unitCentre = ccp(unitBB.origin.x + (unitBB.size.width / 2), 
									 unitBB.origin.y + (unitBB.size.height / 2));
			
			CGRect targetBB = [attackTarget boundingBox];
			CGPoint targetCentre = ccp(targetBB.origin.x + (targetBB.size.width / 2), 
									   targetBB.origin.y + (targetBB.size.height / 2));
			
			CGPoint mid = ccpMidpoint(unitCentre, targetCentre);
			
			ccDrawLine( [self convertToNodeSpace:unitCentre], [self convertToNodeSpace:mid] );
		}
	}
}

-(void)debugRetainCount {
	NSLog( @"Retain Count: %d", [self retainCount] );
}

@end
